import datetime

from rest_framework import serializers
from django_redis import get_redis_connection
from django.db import transaction

from . import models
from course.models import Course
from coupon.models import UserCoupon
from users.models import User


class OrderModelSerializer(serializers.ModelSerializer):
	"""订单序列化器"""

	class Meta:
		model = models.Order
		fields = ["id", "order_number", "pay_type", "credit", "coupon"]
		extra_kwargs = {
			"id": {"read_only": True},
			"order_number": {"read_only": True},
			"pay_type": {"write_only": True},
			"credit": {"write_only": True},
			"coupon": {"write_only": True}
		}

	def validate(self, attrs):
		pay_type = attrs.get('pay_type')

		try:
			models.Order.pay_choices[pay_type]
		except:
			raise serializers.ValidationError('不支持当前所选支付类型')
		# todo 判断积分使用是否上限,总共200个，你发过来2000个，需要判断一下

		# todo 判断优惠券是否满足使用条件，是否存在，或者是否已经过期

		# todo 校验购买的商品课程是否存在
		return attrs

	def create(self, validated_data):
		"""生成订单[使用事务来完成订单的生成]"""
		# 生成唯一订单号[结合时间+用户ID+随机数(递增值<在redis中针对一个数值不断递增>)]
		total_price = r_price = 0
		conn = get_redis_connection('cart')
		coupon = validated_data.get('coupon')
		user_id = self.context['request'].user.id
		# Redis Incr 命令将 key 中储存的数字值增一。
		incr = int(conn.incr('order'))
		order_number = datetime.datetime.now().strftime('%Y%m%d%H%M%S') + '%06d' % user_id + '%06d' % incr
		with transaction.atomic():
			save_id = transaction.savepoint()
			# 生成订单
			order = models.Order.objects.create(
				order_title='黑丝学城的订单',
				total_price=0,
				real_price=0,
				order_number=order_number,
				order_status=0,
				pay_type=validated_data.get('pay_type'),
				credit=validated_data.get('credit', 0),
				coupon=validated_data.get('coupon', 0),
				order_desc='666',
				user_id=user_id
			)

			# 生成订单详情
			cart_byte_dict = conn.hgetall(f'cart_{user_id}')
			selected_byte_list = conn.smembers(f'selected_{user_id}')

			pipe = conn.pipeline()
			pipe.multi()

			# 获取勾选的商品
			for course_id_byte, expire_time_byte in cart_byte_dict.items():
				if course_id_byte in selected_byte_list:
					course_id = int(course_id_byte.decode())
					expire_time = int(expire_time_byte.decode())
					try:
						course = Course.objects.get(is_show=True, is_deleted=False, id=course_id)
					except Course.DoesNotExist:
						raise serializers.ValidationError('该课程不存在或已下架')
					original_price = course.price
					real_price = course.real_price(expire_time)
					models.OrderDetail.objects.create(
						order=order,
						course=course,
						expire=expire_time,
						price=original_price,
						real_price=real_price,
						discount_name=course.discount_name
					)
					pipe.hdel(f'cart_{user_id}', course_id)
					pipe.srem(f'selected_{user_id}', course_id)
					total_price += float(original_price)
					r_price += float(real_price)
			order.total_price = total_price
			order.real_price = r_price
			if coupon > 0:
				try:
					user_coupon = UserCoupon.objects.get(is_show=True, is_deleted=False, id=coupon)
					start_time = user_coupon.start_time.timestamp()
					now_time = datetime.datetime.now().timestamp()
					end_time = start_time + user_coupon.coupon.timer * 24 * 3600
					if start_time > now_time or now_time > end_time:
						transaction.savepoint_rollback(save_id)
						raise serializers.ValidationError("对不起，当前优惠券无法使用！请重新确认使用的优惠券")
					if user_coupon.coupon.condition > total_price:
						transaction.savepoint_rollback(save_id)
						raise serializers.ValidationError("对不起，当前优惠券无法使用！请重新确认使用的优惠券")
					sale_num = float(user_coupon.coupon.sale[1:])
					if user_coupon.coupon.sale[0] == "-":
						# 3.1 抵扣优惠券，实付总金额 = 商品总价 - 优惠券的金额
						order.real_price -= sale_num
					elif user_coupon.coupon.sale[0] == "*":
						# 3.2 折扣优惠券，实付总金额 = 商品总价 * 优惠券的金额
						order.real_price *= sale_num

					# 防止出现无条件使用的优惠券产生负数的实付金额
					if order.real_price < 0:
						order.real_price = 0
				except UserCoupon.DoesNotExist:
					transaction.savepoint_rollback(save_id)
					raise serializers.ValidationError('优惠券不存在或已过期')
			try:
				order.save()
				pipe.execute()
			except:
				transaction.savepoint_rollback(save_id)
				raise serializers.ValidationError('订单生成失败')
		return order


class OrderDetailListModelSerializer(serializers.ModelSerializer):
    class Meta:
        model = models.OrderDetail
        fields = ("price","real_price","discount_name","expire_text","course_img","course_name","course")


class OrderListModelSerializer(serializers.ModelSerializer):
    order_courses = OrderDetailListModelSerializer(many=True)

    class Meta:
        model = models.Order
        fields = ("order_courses", "id", "pay_time", "order_number", "real_price", "total_price", "order_status", "get_order_status_display", "pay_type")


class UserOrderModelSerializer(serializers.ModelSerializer):
    user_orders = OrderListModelSerializer(many=True)

    class Meta:
        model = User
        # fields = ("username","身份信息..")
        fields = ("username", "user_orders")